// Kony


#include "AbilitySystem/BaseAttributeSet.h"

#include "AbilitySystemBlueprintLibrary.h"
#include "GameFramework/Character.h"
#include "Net/UnrealNetwork.h"
#include "AbilitySystemComponent.h"
#include "BaseAbilityTypes.h"
#include "GameplayEffectExtension.h"
#include "BaseGameplayTags.h"
#include "AbilitySystem/BaseAbilitySystemLibrary.h"
#include "GASC_HuanLing/BaseLogChannels.h"
#include "Interaction/CombatInterface.h"
#include "Interaction/PlayerInterface.h"
#include "Kismet/GameplayStatics.h"
#include "Player/BasePlayerController.h"
#include "GameplayEffectComponents/TargetTagsGameplayEffectComponent.h"
/**
 * 这是属性集的基类 .app
 */
UBaseAttributeSet::UBaseAttributeSet()
{
	//初始化属性值 showdebug abilitysystem可以看到当前数据
	//不在这里硬编码初始化了 改成动态赋值
	// InitHealth(50.f);
	// InitMaxHealth(100.f); 改为通过主属性生成
	// InitMana(25.f);
	// InitMaxMana(50.f); 改为通过主属性生成
	//测试用例
	// RandomFunctionPointer = RandomFunction;
	// float F = RandomFunctionPointer(0,0.f,0);

	
	//获取静态游戏标签单例
	const FBaseGameplayTags& GameplayTags = FBaseGameplayTags::Get();
	
	//注册属性集 到 游戏标签广播 这样就可以广播到个人属性菜单中显示
	//主要属性部分
	TagsToAttributes.Add(GameplayTags.Attributes_Primary_Strength, GetStrengthAttribute);
	// Intelligence 法力委托
	TagsToAttributes.Add(GameplayTags.Attributes_Primary_Intelligence, GetIntelligenceAttribute);
	// SoulPower 法力委托
	TagsToAttributes.Add(GameplayTags.Attributes_Primary_SoulPower, GetSoulPowerAttribute);
	// Resilience 体魄委托
	TagsToAttributes.Add(GameplayTags.Attributes_Primary_Resilience, GetResilienceAttribute);
	// Vigor 体魄委托
	TagsToAttributes.Add(GameplayTags.Attributes_Primary_Vigor, GetVigorAttribute);
	// Spirit 灵魂委托
	TagsToAttributes.Add(GameplayTags.Attributes_Primary_Spirit, GetSpiritAttribute);
	// Agility 身法委托
	TagsToAttributes.Add(GameplayTags.Attributes_Primary_Agility, GetAgilityAttribute);
	// Insight 智慧委托
	TagsToAttributes.Add(GameplayTags.Attributes_Primary_Insight, GetInsightAttribute);

	//核心属性部分
	// Health
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_MaxHealth, GetMaxHealthAttribute);
	// MaxMana 法力委托
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_MaxMana, GetMaxManaAttribute);
	// GhostHealth 幽灵生命委托
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_GhostHealth, GetGhostHealthAttribute);
	// GhostMana 幽灵法力委托
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_GhostMana, GetGhostManaAttribute);

	//次要属性部分
	// Armor 护甲
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_Armor, GetArmorAttribute);
	// Armor Penetration 护甲穿透
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_ArmorPenetration, GetArmorPenetrationAttribute);
	// SpellPenetration 法术穿透
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_SpellPenetration, GetSpellPenetrationAttribute);
	// Block Chance 格挡几率
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_BlockChance, GetBlockChanceAttribute);
	// Critical Hit Chance 暴击几率
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_CriticalHitChance, GetCriticalHitChanceAttribute);
	// Critical Hit Damage 暴击伤害
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_CriticalHitDamage, GetCriticalHitDamageAttribute);
	// Critical Hit Resistance 暴击抗性
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_CriticalHitResistance, GetCriticalHitResistanceAttribute);
	// Health Regeneration 生命恢复
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_HealthRegeneration, GetHealthRegenerationAttribute);
	// Mana Regeneration 法力恢复
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_ManaRegeneration, GetManaRegenerationAttribute);
	// MovementSpeed 移动速度
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_MovementSpeed, GetMovementSpeedAttribute);
	// AttackSpeed 攻击速度
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_AttackSpeed, GetAttackSpeedAttribute);
	// SpellCastingSpeed 法术速度
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_SpellCastingSpeed, GetSpellCastingSpeedAttribute);
	// PerceptionRange 感知范围
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_PerceptionRange, GetPerceptionRangeAttribute);
	// HitChance 命中几率	
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_HitChance, GetHitChanceAttribute);
	// DodgeRate 闪避率身法
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_DodgeRate, GetDodgeRateAttribute);
	// SummonDuration 召唤持续时间
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_SummonDuration, GetSummonDurationAttribute);
	//护体罡气 Protective Aura 来源修为等级 和 装备
	TagsToAttributes.Add(GameplayTags.Attributes_Secondary_ProtectiveAura, GetProtectiveAuraAttribute);
	
	//抗性属性部分
	TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Physical, GetPhysicalResistanceAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Magic, GetMagicResistanceAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Summon, GetSummonResistanceAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Fire, GetFireResistanceAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Water, GetWaterResistanceAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Earth, GetEarthResistanceAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Wood, GetWoodResistanceAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Gold, GetGoldResistanceAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Ice, GetIceResistanceAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Lightning, GetLightningResistanceAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Wind, GetWindResistanceAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Poison, GetPoisonResistanceAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Dark, GetDarkResistanceAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Arcane, GetArcaneResistanceAttribute);

	
}

void UBaseAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	//注册等级属性
	// DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, Level, COND_None, REPNOTIFY_Always)
	// DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, XP, COND_None, REPNOTIFY_Always)
	// DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, LingQi, COND_None, REPNOTIFY_Always)
	// DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, Cultivation, COND_None, REPNOTIFY_Always)
	// DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, CultivationTier, COND_None, REPNOTIFY_Always)
	// DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, CultivationStage, COND_None, REPNOTIFY_Always)

	//注册主要属性
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, Strength, COND_None, REPNOTIFY_Always)
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, Intelligence, COND_None, REPNOTIFY_Always)
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, SoulPower, COND_None, REPNOTIFY_Always)
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, Resilience, COND_None, REPNOTIFY_Always)
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, Vigor, COND_None, REPNOTIFY_Always)
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, Spirit, COND_None, REPNOTIFY_Always)
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, Agility, COND_None, REPNOTIFY_Always)
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, Insight, COND_None, REPNOTIFY_Always)

	//注册次要属性
	//注册生命值以进行复制
	//REPNOTIFY_Always 任何时候都复制
	//REPNOTIFY_OnChanged 只有当属性被修改时才复制
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, Health, COND_None, REPNOTIFY_Always)
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, MaxHealth, COND_None, REPNOTIFY_Always)
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, Mana, COND_None, REPNOTIFY_Always)
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, MaxMana, COND_None, REPNOTIFY_Always)
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, GhostHealth, COND_None, REPNOTIFY_Always)
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, GhostMana, COND_None, REPNOTIFY_Always)

	//战斗相关 Secondary 次要属性
	// 	护甲	Armor	韧性
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, Armor, COND_None, REPNOTIFY_Always)
	// 护甲穿透	Armor Penetration	力量
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, ArmorPenetration, COND_None, REPNOTIFY_Always)
	// 法术穿透	SpellPenetration	法力/魂力
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, SpellPenetration, COND_None, REPNOTIFY_Always)
	// 格挡几率	Block Chance	体魄
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, BlockChance, COND_None, REPNOTIFY_Always)
	// 暴击几率	Critical Hit Chance	装备
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, CriticalHitChance, COND_None, REPNOTIFY_Always)
	// 暴击伤害	Critical Hit Damage	装备
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, CriticalHitDamage, COND_None, REPNOTIFY_Always)
	// 暴击抗性	Critical Hit Resistance	装备
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, CriticalHitResistance, COND_None, REPNOTIFY_Always)
	// 生命恢复	Health Regeneration	体魄
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, HealthRegeneration, COND_None, REPNOTIFY_Always)
	// 法力恢复	Mana Regeneration	法力
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, ManaRegeneration, COND_None, REPNOTIFY_Always)

	// 移动速度	MovementSpeed	身法
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, MovementSpeed, COND_None, REPNOTIFY_Always)
	// 攻击速度	AttackSpeed	身法
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, AttackSpeed, COND_None, REPNOTIFY_Always)
	// 施法速度	Spell Casting Speed	身法
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, SpellCastingSpeed, COND_None, REPNOTIFY_Always)
	// 命中几率	Hit Chance	洞察
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, HitChance, COND_None, REPNOTIFY_Always)
	// 闪避率	Dodge Rate	身法
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, DodgeRate, COND_None, REPNOTIFY_Always)
	// 感知范围	Perception Range	神识
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, PerceptionRange, COND_None, REPNOTIFY_Always)
	// 召唤物持续时间	Summon Duration	魂力
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, SummonDuration, COND_None, REPNOTIFY_Always)

	//护体罡气 Protective Aura 来源修为等级 和 装备
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, ProtectiveAura, COND_None, REPNOTIFY_Always)

	//抗性属性
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, PhysicalResistance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, MagicResistance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, SummonResistance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, FireResistance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, WaterResistance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, EarthResistance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, WoodResistance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, GoldResistance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, IceResistance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, LightningResistance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, WindResistance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, PoisonResistance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, DarkResistance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, ArcaneResistance, COND_None, REPNOTIFY_Always);

	
}
// 在属性值改变之前调用，用于对即将改变的值进行约束或修改（用于判断数值计算时少 不可超过限制，避免负数）
void UBaseAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
	float OldHealth = GetHealth();
	Super::PreAttributeChange(Attribute, NewValue);
	float NewHealth = GetHealth();
	
	//判断生命值
	if (Attribute == GetHealthAttribute())
	{
		//设置计算数值不能低于0 不能大于最大值
		NewValue=FMath::Clamp<float>(NewValue, 0.f, GetMaxHealth());
		// UE_LOG(LogTemp, Warning, TEXT("Health: %f"), NewValue);
	}
	//判断魔法值
	if (Attribute == GetManaAttribute())
	{
		NewValue=FMath::Clamp<float>(NewValue, 0.f, GetMaxMana());
	}
	//判断幽灵生命值
	if (Attribute == GetGhostHealthAttribute())
	{
		NewValue=FMath::Clamp<float>(NewValue, 0.f, GetMaxHealth());
	}
	//判断幽灵魔法值
	if (Attribute == GetGhostManaAttribute())
	{
		NewValue=FMath::Clamp<float>(NewValue, 0.f, GetMaxMana());
	}
	
}
//设置效果属性
void UBaseAttributeSet::SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props) const
{
	//处理逻辑
	// Source = causer of the effect,Target = target of the effect (owner of this AS)
	// Source = 效果触发者（造成效果的对象）, Target = 效果目标（该属性集的所有者）
	// FGameplayEffectContextHandle 是GAS系统中用于封装和管理GameplayEffect上下文的智能指针包装类
	//把各种特效属性存储到Props构造体中
	//游戏效果上下文处理器 
	Props.EffectContextHandle = Data.EffectSpec.GetContext();
	//源角色 能力系统组件
	Props.SourceASC = Props.EffectContextHandle.GetOriginalInstigatorAbilitySystemComponent();
	
	if (IsValid(Props.SourceASC) && Props.SourceASC ->AbilityActorInfo.IsValid()
		&& Props.SourceASC->AbilityActorInfo->AvatarActor.IsValid())
	{
		//获取源角色的AvatarActor（通常是角色本身或武器等实体对象）
		Props.SourceAvatarActor = Props.SourceASC ->AbilityActorInfo ->AvatarActor.Get();
		//获取该来源玩家控制器,首先通过获取AbilityActorInfo获取到玩家控制器，
		//如果获取不到，再通过AvatarActor获取转化为Pawn，再通过Pawn获取控制器
		Props.SourceController = Props.SourceASC->AbilityActorInfo->PlayerController.Get();
		if (Props.SourceController == nullptr && Props.SourceAvatarActor != nullptr)
		{
			if (const APawn* Pawn = Cast<APawn>(Props.SourceAvatarActor))
			{
				Props.SourceController = Pawn->GetController();
			}
		}
		//如果控制器不为空，则读取角色
		if (Props.SourceController)
		{
			Props.SourceCharacter = Cast<ACharacter>(Props.SourceController->GetPawn());
		}
	}
	//获取目标角色 能力系统组件
	if (Data.Target.AbilityActorInfo.IsValid() && Data.Target.AbilityActorInfo->AvatarActor.IsValid())
	{
		//获取目标虚拟角色
		Props.TargetAvatarActor = Data.Target.AbilityActorInfo->AvatarActor.Get();
		//获取目标玩家控制器
		Props.TargetController = Data.Target.AbilityActorInfo->PlayerController.Get();
		//获取目标角色
		Props.TargetCharacter = Cast<ACharacter>(Props.TargetAvatarActor);
		//获取目标角色能力系统组件
		Props.TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Props.TargetAvatarActor);
	}
}



//在属性值改变之后调用，用于对改变后的值进行计算和逻辑处理 （处理战斗系统 数据计算）
void UBaseAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
	Super::PostGameplayEffectExecute(Data);
	/**
	 * Data包含 以下信息
	 * EffectSpec: 用于获取效果数据
	 * EvaluatedData: 用于获取属性数据
	 * Target: 用于获取目标对象
	 ***/
	//计算处理逻辑
	// Source = 效果触发者（造成效果的对象）, Target = 效果目标（该属性集的所有者）
	FEffectProperties Props;
	SetEffectProperties(Data,Props);
	//检查目标角色的角色接口
	if (Props.TargetCharacter && Props.TargetCharacter->Implements<UCombatInterface>())
	{
		//判断目标角色是否死亡,如果死亡 什么都不操作直接返回
		if (ICombatInterface::Execute_IsDead(Props.TargetCharacter)) return;
	}
	if (Data.EvaluatedData.Attribute == GetHealthAttribute() || Data.EvaluatedData.Attribute == GetMaxHealthAttribute() || Data.EvaluatedData.Attribute == GetVigorAttribute())
	{
		//如果生命值改变,打印一个debug日志
		// GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Red, FString::Printf(TEXT("Health form GetHealth(): %f"), GetHealth()));
		//这里是属性改变后修改生命值并限制范围，这里修改是为了解决在PreAttributeChange修改只能对表面属性数值看起来修改了 但实际未修改的bug
		//也就是说 这里修改才能实际修改，PreAttributeChange修改只能修改界面显示的数值
		if (Data.EvaluatedData.Attribute == GetHealthAttribute())
		{
			SetHealth(FMath::Clamp(GetHealth(), 0.f, GetMaxHealth()));
			// 检查是否是无限效果或即时效果，如果是则更新幽灵血条
			const bool bIsInfinite = Data.EffectSpec.Def->DurationPolicy == EGameplayEffectDurationType::Infinite;
			const bool bIsInstant = Data.EffectSpec.Def->DurationPolicy == EGameplayEffectDurationType::Instant;
			if (bIsInfinite || bIsInstant)
			{
				// 获取当前效果对Health的影响值
				const float EffectMagnitude = Data.EvaluatedData.Magnitude;
				// 计算新的幽灵血量：当前幽灵血量 + 效果值
				const float NewGhostHealth = GetGhostHealth() + EffectMagnitude;
				SetGhostHealth(FMath::Clamp(NewGhostHealth, 0.f, GetMaxHealth()));
			}
		}else
		{
			SetGhostHealth(FMath::Clamp(GetGhostHealth(), 0.f, GetMaxHealth()));
		}
		// UE_LOG(LogTemp, Warning, TEXT("Changed Health on %s Health: %f"), *Props.TargetAvatarActor->GetName(), GetHealth());
	}
	if (Data.EvaluatedData.Attribute == GetManaAttribute() || Data.EvaluatedData.Attribute == GetMaxManaAttribute() || Data.EvaluatedData.Attribute == GetInsightAttribute() || Data.EvaluatedData.Attribute == GetSoulPowerAttribute())
	{
		if (Data.EvaluatedData.Attribute == GetManaAttribute())
		{
			SetMana(FMath::Clamp(GetMana(), 0.f, GetMaxMana()));
			// 检查是否是无限效果或即时效果，如果是则更新幽灵法力条
	
			const bool bIsInfinite = Data.EffectSpec.Def->DurationPolicy == EGameplayEffectDurationType::Infinite;
			const bool bIsInstant = Data.EffectSpec.Def->DurationPolicy == EGameplayEffectDurationType::Instant;
			if (bIsInfinite || bIsInstant)
			{
				// 获取当前效果对Mana的影响值
				const float EffectMagnitude = Data.EvaluatedData.Magnitude;
				// 计算新的幽灵法力：当前幽灵法力 + 效果值
				const float NewGhostMana = GetGhostMana() + EffectMagnitude;
				SetGhostMana(FMath::Clamp(NewGhostMana, 0.f, GetMaxMana()));
			}
		}else
		{
			SetGhostMana(FMath::Clamp(GetGhostMana(), 0.f, GetMaxMana()));
		}
	}
	//元属性伤害
	if (Data.EvaluatedData.Attribute == GetIncomingDamageAttribute())
	{
		//调用伤害处理函数
		HandleIncomingDamage(Props);
	}
	//获取修为值
	if (Data.EvaluatedData.Attribute == GetIncomingXPAttribute())
	{
		//调用经验处理函数
		HandleIncomingXP(Props);
	}
	//获取灵气值
	if (Data.EvaluatedData.Attribute == GetIncomingLingQiAttribute())
	{
		const float LocalLingQi = GetIncomingLingQi();
		SetIncomingLingQi(0.f);
		//TODO：检查是否升级
		//检查是否实现了玩家接口
		//元角色指定为所有者，GA_ListenForEvents 监听事件应用 GE_EventBasedEffect 会增加 IncomingLingQi(灵气）
		if (Props.SourceCharacter->Implements<UPlayerInterface>())
		{
			IPlayerInterface::Execute_AddToLingQi(Props.SourceCharacter,LocalLingQi);
		}

	}
}
//处理元伤害
void UBaseAttributeSet::HandleIncomingDamage(const FEffectProperties& Props)
{
	//本地传入的伤害值
	const float LocalIncomingDamage = GetIncomingDamage();
	SetIncomingDamage(0.f);
	if (LocalIncomingDamage > 0.f)
	{
		//计算伤害
		const float NewHealth = GetHealth() - LocalIncomingDamage;
		SetHealth(FMath::Clamp(NewHealth, 0.f, GetMaxHealth()));

		//更新幽灵血量 - 当受到伤害时，幽灵血量也应该相应减少
		//这样幽灵球A就能平滑跟随实际血条下降
		const float NewGhostHealth = GetGhostHealth() - LocalIncomingDamage;
		SetGhostHealth(FMath::Clamp(NewGhostHealth, 0.f, GetMaxHealth()));

		//用于判断是否濒死，如果新血量小于=0则为濒死也就是true
		const bool bFatal = NewHealth <= 0.f;
		if (bFatal)
		{
			//濒死处理
			//获取战斗接口
			ICombatInterface* CombatInterface = Cast<ICombatInterface>(Props.TargetAvatarActor);
			if (CombatInterface)
			{
				CombatInterface->Die(UBaseAbilitySystemLibrary::GetDeathImpulse(Props.EffectContextHandle));
			}
			//发送奖励事件、处理怪物死亡获取经验值、灵气等
			SendRewardEvent(Props, FBaseGameplayTags::Get().Attributes_Meta_IncomingXP);
			SendRewardEvent(Props, FBaseGameplayTags::Get().Attributes_Meta_IncomingLingQi);
		}
		else
		{
		
			//获取击退力度
			const FVector& KnockbackForce = UBaseAbilitySystemLibrary::GetKnockbackForce(Props.EffectContextHandle);
			//判断不等于0并且大于1
			if (!KnockbackForce.IsNearlyZero(1.f))
			{
				//让敌人击退
				Props.TargetCharacter->LaunchCharacter(KnockbackForce, true, true);
			}
			//判断目标是否实现了战斗接口 并判断不处于电击状态，因为被电击状态不用显示受击反应
			if (Props.TargetCharacter->Implements<UCombatInterface>() && !ICombatInterface::Execute_IsBeingShocked(Props.TargetCharacter))
			{
				//获取受击能力标签 命中反应
				FGameplayTagContainer TagContainer;
				TagContainer.AddTag(FBaseGameplayTags::Get().Effects_HitReact);
				//使用目标能力系统组件 根据 游戏标签 激活能力
				Props.TargetASC->TryActivateAbilitiesByTag(TagContainer);
			}
		}
		//是否格挡,是否暴击
		const bool bBlocked = UBaseAbilitySystemLibrary::IsBlockedHit(Props.EffectContextHandle);
		const bool bCriticalHit = UBaseAbilitySystemLibrary::IsCriticalHit(Props.EffectContextHandle);
		ShowFloatingText(Props, LocalIncomingDamage, bBlocked, bCriticalHit);
		//触发异常处理
		if (UBaseAbilitySystemLibrary::IsSuccessfulDebuff(Props.EffectContextHandle))
		{
			//处理异常效果
			HandleDebuff(Props);
		}
	}
}
//处理元经验值和灵气值
void UBaseAttributeSet::HandleIncomingXP(const FEffectProperties& Props)
{
	const float LocalIncomingXP = GetIncomingXP();
	SetIncomingXP(0.f);
	// UE_LOG(LogHuanYue, Log,TEXT("获取修为值 %f"), LocalXP);
		
	//检查是否实现了玩家接口
	//元角色指定为所有者，GA_ListenForEvents 监听事件应用 GE_EventBasedEffect 会增加 IncomingXP 修为值（经验值）
	if (Props.SourceCharacter->Implements<UPlayerInterface>() && Props.SourceCharacter->Implements<UCombatInterface>())
	{
		//获取当前等级
		const int32 CurrentLevel = ICombatInterface::Execute_GetPlayerLevel(Props.SourceCharacter);
		//获取当前经验值
		const float CurrentXP = IPlayerInterface::Execute_GetXP(Props.SourceCharacter);
		// //这个是通过当前经验值判断是否升级
		// const int32 NewLevel = IPlayerInterface::Execute_FindLevelForXP(Props.SourceCharacter, CurrentXP + LocalIncomingXP);
		// //如果不升级为0如果升1级为1 依次类推
		//先添加经验值
		IPlayerInterface::Execute_AddToXP(Props.SourceCharacter, LocalIncomingXP);
		//获取新的总经验值
		const float NewTotalXP = CurrentXP + LocalIncomingXP;
		//根据新的总经验值计算应达到的等级
		const int32 NewLevel = IPlayerInterface::Execute_FindLevelForLevelAndXP(Props.SourceCharacter, CurrentLevel, NewTotalXP);
		//计算需要升级的次数
		const int32 NumLevelUps = NewLevel - CurrentLevel;
		//如果需要升级，则循环调用升级函数
		if (NumLevelUps > 0)
		{
			//增加玩家等级
			IPlayerInterface::Execute_AddToPlayerLevel(Props.SourceCharacter, NumLevelUps);
			
			int32 AttributePointsReward = 0;
			int32 SpellPointsReward = 0;
			//循环升级的数量，根据升级的数量 增加属性点和法术点
			for (int32 i = 0; i < NumLevelUps; i++)
			{
				//执行获取升级属性点奖励
				AttributePointsReward += IPlayerInterface::Execute_GetAttributePointsReward(Props.SourceCharacter, CurrentLevel + i);
				//执行获取升级法术点奖励
				SpellPointsReward += IPlayerInterface::Execute_GetSpellPointsReward(Props.SourceCharacter, CurrentLevel + i);
			}
			
			//增加玩家属性点
			IPlayerInterface::Execute_AddToAttributePoints(Props.SourceCharacter, AttributePointsReward);
			//增加玩家法术点
			IPlayerInterface::Execute_AddToSpellPoints(Props.SourceCharacter, SpellPointsReward);
			//补满最大生命和法力值
			bTopOffHealth = true;
			bTopOffMana = true;
			//在角色类执行 升级特效等操作 广播给其他玩家
			IPlayerInterface::Execute_LevelUp(Props.SourceCharacter);
		}
		// IPlayerInterface::Execute_AddToXP(Props.SourceCharacter,LocalIncomingXP);
	}
}
//处理异常效果
void UBaseAttributeSet::HandleDebuff(const FEffectProperties& Props)
{
	const FBaseGameplayTags& GameplayTags = FBaseGameplayTags::Get();
	//获取源能系统组件中的效果上下文
	FGameplayEffectContextHandle EffectContext= Props.SourceASC->MakeEffectContext();
	//添加源对象
	EffectContext.AddSourceObject(Props.SourceAvatarActor);
	//获取伤害类型
	const FGameplayTag DamageType = UBaseAbilitySystemLibrary::GetDamageType(Props.EffectContextHandle);
	//异常效果伤害
	const float DebuffDamage = UBaseAbilitySystemLibrary::GetDebuffDamage(Props.EffectContextHandle);
	//异常效果持续时间
	const float DebuffDuration = UBaseAbilitySystemLibrary::GetDebuffDuration(Props.EffectContextHandle);
	//异常效果频率
	const float DebuffFrequency = UBaseAbilitySystemLibrary::GetDebuffFrequency(Props.EffectContextHandle);
	//把伤害类型作为效果名称 创建游戏效果
	FString DebuffName = FString::Printf(TEXT("DynamicDebuff_%s"),*DamageType.ToString());
	//创建游戏效果
	UGameplayEffect* Effect = NewObject<UGameplayEffect>(GetTransientPackage(),FName(DebuffName));
	//游戏效果设置成 持续时间类型
	Effect->DurationPolicy = EGameplayEffectDurationType::HasDuration;
	//设置频率
	Effect->Period = DebuffFrequency;
	//设置持续时间
	Effect->DurationMagnitude = FScalableFloat(DebuffDuration);
	//设置效果
	// Effect->InheritableOwnedTagsContainer.AddTag(GameplayTags.DamageTypesToDebuffs[DamageType]);
	//设置效果 - 使用新的UTargetTagsGameplayEffectComponent替代已弃用的InheritableOwnedTagsContainer
	FInheritedTagContainer TagContainer = FInheritedTagContainer();
	UTargetTagsGameplayEffectComponent& Component = Effect->FindOrAddComponent<UTargetTagsGameplayEffectComponent>();//这里是新增的内容 直到下面那个if结束
	const FGameplayTag DebuffTag = GameplayTags.DamageTypesToDebuffs[DamageType];
	TagContainer.Added.AddTag(DebuffTag);
	//当添加了眩晕和击倒的时候，添加输入锁定标签避免可以操作转向等
	if (DebuffTag.MatchesTagExact(GameplayTags.Debuff_Propertie_Stun) || DebuffTag.MatchesTagExact(GameplayTags.Debuff_Propertie_Down))
	{
		TagContainer.Added.AddTag(GameplayTags.Player_Block_InputHeld);
		TagContainer.Added.AddTag(GameplayTags.Player_Block_InputPressed);
		TagContainer.Added.AddTag(GameplayTags.Player_Block_InputReleased);
		TagContainer.Added.AddTag(GameplayTags.Player_Block_CursorTrace);
	}
	Component.SetAndApplyTargetTagChanges(TagContainer);
	//设置堆叠类型为按照来源堆叠 和 堆叠数量 1
	Effect->StackingType = EGameplayEffectStackingType::AggregateBySource;
	Effect->StackLimitCount = 1;
	//设置修饰符（这个是重点了 这个可以用于伤害或者减速 减少属性等）
	//这里因为只用一次 所以设置为const，如果以后拓展多种效果就改为动态
	const int32 Index = Effect->Modifiers.Num();
	Effect->Modifiers.Add(FGameplayModifierInfo());
	FGameplayModifierInfo& ModifierInfo = Effect->Modifiers[Index];
	//修改器 运算符操作 设置为加法 
	ModifierInfo.ModifierOp = EGameplayModOp::Additive;
	//设置幅度值 伤害
	ModifierInfo.ModifierMagnitude = FScalableFloat(DebuffDamage);
	//设置修改的属性 这里设置元伤害
	ModifierInfo.Attribute = UBaseAttributeSet::GetIncomingDamageAttribute();
    //创建新游戏效果规格 用于触发上面创建的异常效果
	//注意新的用于异常效果的游戏效果 不要添加任何异常类的效果，否则会导致无限循环
	FGameplayEffectSpec* MutableSpec = new FGameplayEffectSpec(Effect, EffectContext, 1.f);
	if (MutableSpec)
	{
		//获取游戏效果上下文
		FBaseGameplayEffectContext* BaseContext = static_cast<FBaseGameplayEffectContext*>(MutableSpec->GetContext().Get());
		//创建新共享指针
		TSharedPtr<FGameplayTag> DebuffDamageType = MakeShareable(new FGameplayTag(DamageType));
		//设置伤害类型
		BaseContext->SetDamageType(DebuffDamageType);
	}
	//对目标应用游戏效果
	Props.TargetASC->ApplyGameplayEffectSpecToSelf(*MutableSpec);
	
}

//在属性值改变之后调用，用于处理属性变化后的逻辑（如升级后属性调整后，这里可以用于补充当前生命值等）
void UBaseAttributeSet::PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue)
{
	Super::PostAttributeChange(Attribute, OldValue, NewValue);
	//如果是升级 不满生命值和法力值
	if (Attribute == GetMaxHealthAttribute() && bTopOffHealth)
	{
		SetHealth(GetMaxHealth());
		bTopOffHealth = false;
	}
	if (Attribute == GetMaxManaAttribute() && bTopOffMana)
	{
		SetMana(GetMaxMana());
		bTopOffMana = false;
	}
	
}

//显示浮动伤害数字
void UBaseAttributeSet::ShowFloatingText(const FEffectProperties& Props, float Damage, bool bBlockedHit, bool bCriticalHit) const
{
	//判断是否是自己造成的伤害
	if (Props.SourceCharacter!=Props.TargetCharacter)
	{
		//UGameplayStatics::GetPlayerController(Props.SourceCharacter,0)) 旧版写法 这个无法获取到正确的客户端玩家控制器
		//使用 Props.SourceCharacter->Controller 这样获取正确的 客户端控制器 解决 客户端 伤害显示在服务器的问题
		if (ABasePlayerController* PC = Cast<ABasePlayerController>(Props.SourceCharacter->Controller))
		{
			PC->ShowDamageNumber(Damage, Props.TargetCharacter, bBlockedHit, bCriticalHit);
			return;
		}
		//这部分是解决怪物攻击玩家不显示数字问题
		if (ABasePlayerController* PC = Cast<ABasePlayerController>(Props.TargetCharacter->Controller))
		{
			PC->ShowDamageNumber(Damage, Props.TargetCharacter, bBlockedHit, bCriticalHit);
		}
	}
}
//发送获取 经验值/修为值 事件
void UBaseAttributeSet::SendRewardEvent(const FEffectProperties& Props,const FGameplayTag& GameplayTag) const
{
	//空指针检查
	if (!Props.TargetAvatarActor || !Props.SourceCharacter) return;
	
	//获取目标的战斗接口，从目标战斗接口中取出 目标的等级 和 职业类别 用于计算 这个职业对应级别的修为值
	if (Props.TargetAvatarActor->Implements<UCombatInterface>())
	{
		//获取目标的等级
		const int32 TargetLevel = ICombatInterface::Execute_GetPlayerLevel(Props.TargetAvatarActor);
		//获取目标职业类别, 因为这个函数是蓝图原生事件的函数，所以这里必须使用 Execute 执行版本 否则会报错
		const ECharacterClass TargetClass = ICombatInterface::Execute_GetCharacterClass(Props.TargetAvatarActor);
		
		float Reward = 0.f;
		const FBaseGameplayTags& GameplayTags = FBaseGameplayTags::Get();
		//根据不同的GameplayTag类型获取对应的奖励值
		if (GameplayTag == GameplayTags.Attributes_Meta_IncomingXP)
		{
			//获取经验值奖励
			Reward = UBaseAbilitySystemLibrary::GetXPRewardForClassAndLevel(Props.TargetCharacter, TargetClass, TargetLevel);
		}
		else if (GameplayTag == GameplayTags.Attributes_Meta_IncomingLingQi)
		{
			//获取灵气奖励
			Reward = UBaseAbilitySystemLibrary::GetLingQiRewardForClassAndLevel(Props.TargetCharacter, TargetClass, TargetLevel);
		}
		//有效载荷量，也就是发送事件时携带的数据，蓝图中Break GameplayEventData可以获取到这些数据
		FGameplayEventData Payload;
		Payload.EventTag = GameplayTag;
		Payload.EventMagnitude = Reward;
		//发送事件 给源角色 也就是施法者
		UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(Props.SourceCharacter, GameplayTag, Payload);
	}
}



void UBaseAttributeSet::SetGhost(const FGameplayEffectSpecHandle EffectSpecHandle)
{
    if (!EffectSpecHandle.Data.IsValid())
        return;

	const TArray<FGameplayModifierInfo>& ModifierInfos = EffectSpecHandle.Data->Def.Get()->Modifiers;
	
	// 判断效果类型
	const bool bHasDuration = EffectSpecHandle.Data.Get()->Def.Get()->DurationPolicy == EGameplayEffectDurationType::HasDuration;

	// SetGhost 只处理持续效果，即时和无限效果在 PostGameplayEffectExecute 中处理
	if (!bHasDuration)
	{
		return;
	}

	for (int32 i = 0; i < ModifierInfos.Num(); ++i)
	{
		const FGameplayModifierInfo& ModifierInfo = ModifierInfos[i];

		if (ModifierInfo.Attribute == GetHealthAttribute() || ModifierInfo.Attribute == GetMaxHealthAttribute() || ModifierInfo.Attribute == GetVigorAttribute())
		{
			if (ModifierInfo.Attribute == GetHealthAttribute())
			{
				float EffectValue = 0.f;
				// 使用 AttemptCalculateMagnitude 方法手动计算 Magnitude 值
				if (ModifierInfo.ModifierMagnitude.AttemptCalculateMagnitude(*EffectSpecHandle.Data.Get(), EffectValue, false, 0.f))
				{
					// 持续效果：计算总的周期性效果
					const float Duration = EffectSpecHandle.Data->GetDuration();
					const float Period = EffectSpecHandle.Data->GetPeriod();
					if (Duration > 0.f && Period > 0.f)
					{
						int32 NumTicks = FMath::FloorToInt(Duration / Period);
						float TotalHeal = EffectValue * NumTicks;
						float FinalHealth = GetHealth() + TotalHeal;
						
						// 限制在最大值范围内
						FinalHealth = FMath::Clamp(FinalHealth, 0.f, GetMaxHealth());
						SetGhostHealth(FinalHealth);
					}
				}
			}else
			{
				// 限制在最大值范围内
				SetGhostHealth(FMath::Clamp(GetGhostHealth(), 0.f, GetMaxHealth()));
			}
		}
		else if (ModifierInfo.Attribute == GetManaAttribute() || ModifierInfo.Attribute == GetMaxManaAttribute() || ModifierInfo.Attribute == GetInsightAttribute() || ModifierInfo.Attribute == GetSoulPowerAttribute())
		{
			if (ModifierInfo.Attribute == GetManaAttribute())
			{
				float EffectValue = 0.f;
				// 使用 AttemptCalculateMagnitude 方法手动计算 Magnitude 值
				if (ModifierInfo.ModifierMagnitude.AttemptCalculateMagnitude(*EffectSpecHandle.Data.Get(), EffectValue, false, 0.f))
				{
					// 持续效果：计算总的周期性效果
					const float Duration = EffectSpecHandle.Data->GetDuration();
					const float Period = EffectSpecHandle.Data->GetPeriod();
					if (Duration > 0.f && Period > 0.f)
					{
						int32 NumTicks = FMath::FloorToInt(Duration / Period);
						float TotalMana = EffectValue * NumTicks;
						float FinalMana = GetMana() + TotalMana;
						
						// 限制在最大值范围内
						FinalMana = FMath::Clamp(FinalMana, 0.f, GetMaxMana());
						SetGhostMana(FinalMana);
					}
				}
			}
			else
			{
				// 限制在最大值范围内
				SetGhostMana(FMath::Clamp(GetGhostMana(), 0.f, GetMaxMana()));
			}
		}
	}
}

//等级属性部分
// void UBaseAttributeSet::OnRep_Level(const FGameplayAttributeData& OldLevel) const
// {
// 	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, Level, OldLevel);
// }
//
// void UBaseAttributeSet::OnRep_XP(const FGameplayAttributeData& OldXP) const
// {
// 	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, XP, OldXP);
// }
//
// void UBaseAttributeSet::OnRep_LingQi(const FGameplayAttributeData& OldLingQi) const
// {
// 	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, LingQi, OldLingQi);
// }
//
// void UBaseAttributeSet::OnRep_Cultivation(const FGameplayAttributeData& OldCultivation) const
// {
// 	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, Cultivation, OldCultivation);
// }
//
// void UBaseAttributeSet::OnRep_CultivationTier(const FGameplayAttributeData& OldCultivationTier) const
// {
// 	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, CultivationTier, OldCultivationTier);
// }
//
// void UBaseAttributeSet::OnRep_CultivationStage(const FGameplayAttributeData& OldCultivationStage) const
// {
// 	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, CultivationStage, OldCultivationStage);
// }

//主要属性部分
void UBaseAttributeSet::OnRep_Strength(const FGameplayAttributeData& OldStrength) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, Strength, OldStrength);
}

void UBaseAttributeSet::OnRep_Intelligence(const FGameplayAttributeData& OldIntelligence) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, Intelligence, OldIntelligence);
}

void UBaseAttributeSet::OnRep_SoulPower(const FGameplayAttributeData& OldSoulPower) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, SoulPower, OldSoulPower);
}

void UBaseAttributeSet::OnRep_Resilience(const FGameplayAttributeData& OldResilience) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, Resilience, OldResilience);
}

void UBaseAttributeSet::OnRep_Vigor(const FGameplayAttributeData& OldVigor) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, Vigor, OldVigor);
}

void UBaseAttributeSet::OnRep_Spirit(const FGameplayAttributeData& OldSpirit) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, Spirit, OldSpirit);
}

void UBaseAttributeSet::OnRep_Agility(const FGameplayAttributeData& OldAgility) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, Agility, OldAgility);
}

void UBaseAttributeSet::OnRep_Insight(const FGameplayAttributeData& OldInsight) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, Insight, OldInsight);
}


//下面是 次要属性
void UBaseAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth) const
{
	//这是服务端的下发回调函数，当Health属性被修改时，会调用这个函数。
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, Health, OldHealth);
}
void UBaseAttributeSet::OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, MaxHealth, OldMaxHealth);
}

void UBaseAttributeSet::OnRep_Mana(const FGameplayAttributeData& OldMana) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, Mana, OldMana);
}

void UBaseAttributeSet::OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, MaxMana, OldMaxMana);
}

void UBaseAttributeSet::OnRep_GhostHealth(const FGameplayAttributeData& OldGhostHealth) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, GhostHealth, OldGhostHealth);
}

void UBaseAttributeSet::OnRep_GhostMana(const FGameplayAttributeData& OldGhostMana) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, GhostMana, OldGhostMana);
}


void UBaseAttributeSet::OnRep_Armor(const FGameplayAttributeData& OldArmor) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, Armor, OldArmor);
}

void UBaseAttributeSet::OnRep_ArmorPenetration(const FGameplayAttributeData& OldArmorPenetration) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, ArmorPenetration, OldArmorPenetration);
}

void UBaseAttributeSet::OnRep_SpellPenetration(const FGameplayAttributeData& OldSpellPenetration) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, SpellPenetration, OldSpellPenetration);
}

void UBaseAttributeSet::OnRep_BlockChance(const FGameplayAttributeData& OldBlockChance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, BlockChance, OldBlockChance);
}

void UBaseAttributeSet::OnRep_CriticalHitChance(const FGameplayAttributeData& OldCriticalHitChance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, CriticalHitChance, OldCriticalHitChance);
}

void UBaseAttributeSet::OnRep_CriticalHitDamage(const FGameplayAttributeData& OldCriticalHitDamage) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, CriticalHitDamage, OldCriticalHitDamage);
}

void UBaseAttributeSet::OnRep_CriticalHitResistance(const FGameplayAttributeData& OldCriticalHitResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, CriticalHitResistance, OldCriticalHitResistance);
}

void UBaseAttributeSet::OnRep_HealthRegeneration(const FGameplayAttributeData& OldHealthRegeneration) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, HealthRegeneration, OldHealthRegeneration);
}

void UBaseAttributeSet::OnRep_ManaRegeneration(const FGameplayAttributeData& OldManaRegeneration) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, ManaRegeneration, OldManaRegeneration);
}

void UBaseAttributeSet::OnRep_MovementSpeed(const FGameplayAttributeData& OldMovementSpeed) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, MovementSpeed, OldMovementSpeed);
}

void UBaseAttributeSet::OnRep_AttackSpeed(const FGameplayAttributeData& OldAttackSpeed) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, AttackSpeed, OldAttackSpeed);
}

void UBaseAttributeSet::OnRep_SpellCastingSpeed(const FGameplayAttributeData& OldSpellCastingSpeed) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, SpellCastingSpeed, OldSpellCastingSpeed);
}

void UBaseAttributeSet::OnRep_DodgeRate(const FGameplayAttributeData& OldDodgeRate) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, DodgeRate, OldDodgeRate);
}

void UBaseAttributeSet::OnRep_HitChance(const FGameplayAttributeData& OldHitChance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, HitChance, OldHitChance);
}

void UBaseAttributeSet::OnRep_PerceptionRange(const FGameplayAttributeData& OldPerceptionRange) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, PerceptionRange, OldPerceptionRange);
}

void UBaseAttributeSet::OnRep_SummonDuration(const FGameplayAttributeData& OldSummonDuration) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, SummonDuration, OldSummonDuration);
}

void UBaseAttributeSet::OnRep_ProtectiveAura(const FGameplayAttributeData& OldProtectiveAura) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, ProtectiveAura, OldProtectiveAura);
}

void UBaseAttributeSet::OnRep_PhysicalResistance(const FGameplayAttributeData& OldPhysicalResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, PhysicalResistance, OldPhysicalResistance);
}

void UBaseAttributeSet::OnRep_MagicResistance(const FGameplayAttributeData& OldMagicResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, MagicResistance, OldMagicResistance);
}

void UBaseAttributeSet::OnRep_SummonResistance(const FGameplayAttributeData& OldSummonResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, SummonResistance, OldSummonResistance);
}

void UBaseAttributeSet::OnRep_FireResistance(const FGameplayAttributeData& OldFireResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, FireResistance, OldFireResistance);
}

void UBaseAttributeSet::OnRep_WaterResistance(const FGameplayAttributeData& OldWaterResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, WaterResistance, OldWaterResistance);
}

void UBaseAttributeSet::OnRep_EarthResistance(const FGameplayAttributeData& OldEarthResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, EarthResistance, OldEarthResistance);
}

void UBaseAttributeSet::OnRep_WoodResistance(const FGameplayAttributeData& OldWoodResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, WoodResistance, OldWoodResistance);
}

void UBaseAttributeSet::OnRep_GoldResistance(const FGameplayAttributeData& OldGoldResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, GoldResistance, OldGoldResistance);
}

void UBaseAttributeSet::OnRep_IceResistance(const FGameplayAttributeData& OldIceResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, IceResistance, OldIceResistance);
}

void UBaseAttributeSet::OnRep_LightningResistance(const FGameplayAttributeData& OldLightningResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, LightningResistance, OldLightningResistance);
}

void UBaseAttributeSet::OnRep_WindResistance(const FGameplayAttributeData& OldWindResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, WindResistance, OldWindResistance);
}

void UBaseAttributeSet::OnRep_PoisonResistance(const FGameplayAttributeData& OldPoisonResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, PoisonResistance, OldPoisonResistance);
}

void UBaseAttributeSet::OnRep_DarkResistance(const FGameplayAttributeData& OldDarkResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, DarkResistance, OldDarkResistance);
}

void UBaseAttributeSet::OnRep_ArcaneResistance(const FGameplayAttributeData& OldArcaneResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, ArcaneResistance, OldArcaneResistance);
}

